package com.leosoft.heatmonitor.dao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Component;

import com.leosoft.heatmonitor.model.Device;
import com.leosoft.heatmonitor.model.Project;
import com.leosoft.heatmonitor.model.Target;

@Component
public class TargetDAO extends BaseDAO {

	public Map<String, Object> list(int startIndex, int length, List<String[]> wherePart, List<String[]> odrerPart,
			String userId) {
		Object total = new Object();
		Criteria c = this.getSession().createCriteria(Target.class);
		if (!userId.isEmpty()) {
			c = c.createCriteria("project");
			c = c.createCriteria("users");
			c = c.add(Restrictions.eq("id", userId));
			c.setCacheable(true);
			c.setProjection(Projections.rowCount());
			total = c.uniqueResult();
			c = this.getSession().createCriteria(Target.class);
			c.setProjection(Projections.rowCount());
		} else {
			c.setCacheable(true);
			c.setProjection(Projections.rowCount());
			total = c.uniqueResult();
		}

		for (String[] order : odrerPart) {
			if (!order[0].equals("projectName")) {
				if (order[1].equals("desc")) {
					c.addOrder(Order.desc(order[0]));
				} else {
					c.addOrder(Order.asc(order[0]));
				}
			}
		}
		for (String[] where : wherePart) {
			if (!where[0].equals("projectName")) {
				c = c.add(Restrictions.like(where[0], where[1], MatchMode.ANYWHERE));
			}
		}

		c = c.createCriteria("project");
		for (String[] order : odrerPart) {
			if (order[0].equals("projectName")) {
				if (order[1].equals("desc")) {
					c.addOrder(Order.desc("name"));
				} else {
					c.addOrder(Order.asc("name"));
				}
			}
		}
		for (String[] where : wherePart) {
			if (where[0].equals("projectName")) {
				c = c.add(Restrictions.like("name", where[1], MatchMode.ANYWHERE));
			}
		}
		if (!userId.isEmpty()) {
			c = c.createCriteria("users");
			c = c.add(Restrictions.eq("id", userId));
		}
		Object recordsFiltered = c.uniqueResult();
		c.setProjection(null);
		c.setFirstResult(startIndex);
		c.setMaxResults(length);
		List<Target> targets = c.list();
		List<Map<String, String>> datas = new ArrayList<>();
		for (Target target : targets) {
			Map<String, String> data = new HashMap<>();
			data.put("projectName", target.getProject().getName());
			data.put("building", target.getBuilding());
			data.put("door", target.getDoor());
			data.put("user", target.getUser());
			data.put("key", target.getKey());
			data.put("targetname", target.getName());
			data.put("telephone", target.getTelephone());
			data.put("id", target.getId());
			datas.add(data);
		}
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("recordsTotal", total);
		result.put("recordsFiltered", recordsFiltered);
		result.put("data", datas);
		return result;
	}

	public boolean notExist(String projectID, String building, String door, String user) {
		Criteria c = this.getSession().createCriteria(Target.class);
		c = c.add(Restrictions.eq("building", building));
		c = c.add(Restrictions.eq("door", door));
		c = c.add(Restrictions.eq("user", user));
		c = c.createCriteria("project");
		c = c.add(Restrictions.eq("id", projectID));
		return c.list().isEmpty();
	}

	public void create(Project project, String building, String door, String user, String key, String name,
			String telephone) {
		Target target = new Target();
		target.setProject(project);
		target.setKey(key);
		target.setBuilding(building);
		target.setDoor(door);
		target.setUser(user);
		target.setName(name);
		target.setTelephone(telephone);
		target.setDevices(null);
		this.getSession().merge(target);
	}

	public Target getTargetById(String id) {
		Criteria c = this.getSession().createCriteria(Target.class);
		c = c.add(Restrictions.eq("id", id));
		return (Target) c.uniqueResult();
	}

	public void delete(String id) {
		Target target = getTargetById(id);
		this.getSession().delete(target);
	}

	public Project loadProject(String id) {
		Target target = getTargetById(id);
		return target.getProject();
	}

	public void update(String id, Project project, String building, String door, String user, String key, String name,
			String telephone) {
		Target target = getTargetById(id);
		target.setBuilding(building);
		target.setDoor(door);
		target.setKey(key);
		target.setProject(project);
		target.setUser(user);
		target.setName(name);
		target.setTelephone(telephone);
		this.getSession().merge(target);

	}

	public List<Map<String, Object>> loadTarget(String projectId, String deviceId) {
		Criteria c = this.getSession().createCriteria(Target.class);
		c = c.createCriteria("project");
		c = c.add(Restrictions.eq("id", projectId));
		List<Target> targets = c.list();
		List<Map<String, Object>> result = new ArrayList<>();
		for (Target target : targets) {
			int flagBuilding = 0;
			for (Map<String, Object> building : result) {
				if (building.get("title").equals(target.getBuilding())) {
					List<Map<String, Object>> doors = (List<Map<String, Object>>) building.get("children");
					int flagDoor = 0;
					for (Map<String, Object> door : doors) {
						if (door.get("title").equals(target.getDoor())) {
							List<Map<String, Object>> users = (List<Map<String, Object>>) door.get("children");
							Map<String, Object> user = new HashMap<>();
							user.put("key", target.getId());
							List<Device> targetDevices = target.getDevices();
							if (targetDevices.isEmpty()) {
								user.put("title", target.getUser());
							} else {
								Device targetUniqueDevice = targetDevices.get(0);
								if (deviceId.equals(targetUniqueDevice.getId())) {
									user.put("title", target.getUser());
								} else {
									user.put("unselectable", true);
									user.put("hideCheckbox", true);
									user.put("title", target.getUser() + " (设备Key为" + targetUniqueDevice.getKey() + ")");
								}
							}

							users.add(user);

							flagDoor = 1;
						}
					}
					if (flagDoor == 0) {
						Map<String, Object> user = new HashMap<>();
						user.put("key", target.getId());
						if (!target.getDevices().isEmpty()) {
							if (!target.getDevices().get(0).getId().equals(deviceId)) {
								user.put("unselectable", true);
								user.put("hideCheckbox", true);
								user.put("title", target.getUser() + " (设备Key为" + target.getDevices().get(0).getKey()
										+ ")");
							} else {
								user.put("title", target.getUser());
							}
						} else {
							user.put("title", target.getUser());
						}
						List<Map<String, Object>> users = new ArrayList<>();
						users.add(user);
						Map<String, Object> door = new HashMap<>();
						door.put("title", target.getDoor());
						door.put("children", users);
						door.put("isFolder", true);
						doors.add(door);
					}
					building.put("children", doors);

					flagBuilding = 1;
					break;
				}
			}
			if (flagBuilding == 0) {
				Map<String, Object> user = new HashMap<>();
				List<Device> targetDevices = target.getDevices();
				if (targetDevices.isEmpty()) {
					user.put("title", target.getUser());
				} else {
					Device targetUniqueDevice = targetDevices.get(0);
					if (deviceId.equals(targetUniqueDevice.getId())) {
						user.put("title", target.getUser());
					} else {
						user.put("unselectable", true);
						user.put("hideCheckbox", true);
						user.put("title", target.getUser() + " (设备Key为" + targetUniqueDevice.getKey() + ")");
					}
				}
				user.put("key", target.getId());
				List<Map<String, Object>> users = new ArrayList<>();
				users.add(user);
				Map<String, Object> door = new HashMap<>();
				door.put("title", target.getDoor());
				door.put("children", users);
				door.put("isFolder", true);
				List<Map<String, Object>> doors = new ArrayList<>();
				doors.add(door);
				Map<String, Object> building = new HashMap<>();
				building.put("title", target.getBuilding());
				building.put("children", doors);
				building.put("isFolder", true);
				result.add(building);
			}
		}
		return result;
	}

	public List<Map<String, Object>> loadArea(String projectId) {
		Criteria c = this.getSession().createCriteria(Target.class);
		ProjectionList projectionList = Projections.projectionList();
		projectionList = projectionList.add(Projections.groupProperty("building"));
		projectionList = projectionList.add(Projections.groupProperty("door"));
		c.setProjection(projectionList);
		c = c.createCriteria("project");
		c = c.add(Restrictions.eq("id", projectId));
		List<Object[]> targets = c.list();
		List<Map<String, Object>> result = new ArrayList<>();
		for (Object[] target : targets) {
			int flagBuilding = 0;
			for (Map<String, Object> building : result) {
				if (building.get("title").equals(target[0].toString())) {
					List<Map<String, Object>> doors = (List<Map<String, Object>>) building.get("children");
					Map<String, Object> door = new HashMap<>();
					door.put("title", target[1].toString());
					doors.add(door);
					building.put("children", doors);
					flagBuilding = 1;
				}
			}
			if (flagBuilding == 0) {
				Map<String, Object> door = new HashMap<>();
				door.put("title", target[0].toString());
				List<Map<String, Object>> doors = new ArrayList<>();
				doors.add(door);
				Map<String, Object> building = new HashMap<>();
				building.put("title", target[1].toString());
				building.put("children", doors);
				building.put("isFolder", true);
				result.add(building);
			}
		}
		return result;
	}

	public List<Object> loadBuilding(String projectId) {
		Criteria c = this.getSession().createCriteria(Target.class);
		c.setProjection(Projections.groupProperty("building"));
		c = c.createCriteria("project");
		c = c.add(Restrictions.eq("id", projectId));
		return c.list();
	}

	public List<Object> loadDoor(String projectId, String building) {
		Criteria c = this.getSession().createCriteria(Target.class);
		c.setProjection(Projections.groupProperty("door"));
		c = c.add(Restrictions.eq("building", building));
		c = c.createCriteria("project");
		c = c.add(Restrictions.eq("id", projectId));
		return c.list();
	}

	public List<String> suggestBuilding(String building, String userId) {
		Criteria c = this.getSession().createCriteria(Target.class);
		c.add(Restrictions.like("building", building, MatchMode.START));
		c.setProjection(Projections.groupProperty("building"));
		if (!userId.isEmpty()) {
			c = c.createCriteria("project");
			c = c.createCriteria("users");
			c = c.add(Restrictions.eq("id", userId));
		}
		return c.list();
	}

	public List<String> suggestDoor(String door, String userId) {
		Criteria c = this.getSession().createCriteria(Target.class);
		c.add(Restrictions.like("door", door, MatchMode.START));
		c.setProjection(Projections.groupProperty("door"));
		if (!userId.isEmpty()) {
			c = c.createCriteria("project");
			c = c.createCriteria("users");
			c = c.add(Restrictions.eq("id", userId));
		}
		return c.list();
	}

	public List<String> suggestUser(String user, String userId) {
		Criteria c = this.getSession().createCriteria(Target.class);
		c.add(Restrictions.like("user", user, MatchMode.START));
		c.setProjection(Projections.groupProperty("user"));
		if (!userId.isEmpty()) {
			c = c.createCriteria("project");
			c = c.createCriteria("users");
			c = c.add(Restrictions.eq("id", userId));
		}
		return c.list();
	}

	public List<String> suggestKey(String key, String userId) {
		Criteria c = this.getSession().createCriteria(Target.class);
		c.add(Restrictions.like("key", key, MatchMode.START));
		c.setProjection(Projections.groupProperty("key"));
		if (!userId.isEmpty()) {
			c = c.createCriteria("project");
			c = c.createCriteria("users");
			c = c.add(Restrictions.eq("id", userId));
		}
		return c.list();
	}

	public void upload(List<Target> targets) {
		Session session = this.getSession();
		for (Target target : targets) {
			session.save(target);
		}
	}
}
